// 
// Copyright (c) 2008, Sergey Parshin (quarck@gmail.com)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Sergey Parshin name may not be used to endorse or promote products 
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS I
// NTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//

#ifndef __ITL_AUTO_OBJ_H__
#define __ITL_AUTO_OBJ_H__

namespace itl
{

template <typename T, typename R, R RFn(T obj)>
class auto_xxx
{
	bool 	owns;
	T 	obj;

	typedef auto_xxx<T,R,RFn> this_type;

	// This class of wrapper is only for automatic deallocation of the T object by
	// calling RFn in the destructor. 
	// Copying is not permitted.
	auto_xxx(const this_type& other);
	this_type& operator=(const this_type& other);
public:

	auto_xxx(T o)
		: owns(true)
		, obj(o)
	{
	}

	~auto_xxx()
	{
		if (owns)
			RFn(obj);
	}

	T& get()
	{
		return obj;
	}

	template <typename C>
	C to() const
	{
		return reinterpret_cast<C>(obj);
	}

	operator T() const
	{
		return obj;
	}

	T& withdraw()
	{
		owns = false;
		return obj;
	}
};

}; // namespace itl


#endif
